package net.takela.common.spring.http;

import net.takela.common.utils.JSONUtils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;

import java.util.Arrays;
import java.util.Map;
import java.util.function.Function;

/**
 * @author baboy
 * create at 2023/1/22
 */
public class HttpRequest<T> {
    private RestTemplate restTemplate;
    private HttpMethod httpMethod;
    private Map<String, String> requestHeaders;
    private Object requestBody;
    private Map<String, Object> queryParams;
    private Class<T> resultType;
    private String url;
    private Map<String, Object> uriVariables;
    /**
     * 
     */
    public HttpRequest(RestTemplate restTemplate){
        this.restTemplate = restTemplate;
    }
    /**
     * 
     */
    public RestTemplate getRestTemplate() {
        return restTemplate;
    }
    /**
     * 
     */
    public void setRestTemplate(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }
    /**
     * 
     */
    public HttpMethod getHttpMethod() {
        return httpMethod;
    }
    /**
     * 
     */
    public void setHttpMethod(HttpMethod httpMethod) {
        this.httpMethod = httpMethod;
    }

    public Map<String, String> getRequestHeaders() {
        return requestHeaders;
    }
    /**
     * 
     */
    public void setRequestHeaders(Map<String, String> requestHeaders) {
        this.requestHeaders = requestHeaders;
    }
    /**
     * 
     */
    public Object getRequestBody() {
        return requestBody;
    }
    /**
     * 
     */
    public void setRequestBody(Object requestBody) {
        this.requestBody = requestBody;
    }
    /**
     * 
     */
    public Map getQueryParams() {
        return queryParams;
    }
    /**
     * 
     */
    public void setQueryParams(Map queryParams) {
        this.queryParams = queryParams;
    }
    /**
     * 
     */
    public Class<T> getResultType() {
        return resultType;
    }
    /**
     * 
     */
    public void setResultType(Class<T> resultType) {
        this.resultType = resultType;
    }
    /**
     * 
     */
    public String getUrl() {
        return url;
    }
    /**
     * 
     */
    public void setUrl(String url) {
        this.url = url;
    }

    public Map<String, Object> getUriVariables() {
        return uriVariables;
    }
    /**
     * 
     */
    public void setUriVariables(Map<String, Object> uriVariables) {
        this.uriVariables = uriVariables;
    }
    /**
     * 
     */
    public T request() {
        String url = this.url;
        HttpHeaders headers = new HttpHeaders();
        ObjectMapper mapper = new ObjectMapper();
        org.springframework.http.HttpEntity<Object> requestEntity = null;
//        headers.add("Accept", "application/json");
//        headers.add("Content-Encoding", "UTF-8");
//        headers.add("Content-Type", "application/json; charset=UTF-8");
        //判断是否还有额外的请求头
//        headers.addAll(requestHeader);
        if (null != requestHeaders && !requestHeaders.isEmpty()) {
            for (Map.Entry<String, String> entry : requestHeaders.entrySet()) {
                headers.put(entry.getKey(), Arrays.asList(entry.getValue()));
            }
        }
        Object data = null;
        //按json提交数据
        boolean isPostJson = headers.containsKey("Content-Type") && headers.get("Content-Type").toString().toLowerCase().indexOf("application/json") >= 0;
        //按表单提交数据
        boolean isPostForm = headers.containsKey("Content-Type") && headers.get("Content-Type").toString().toLowerCase().indexOf("form") >= 0;

        if (queryParams !=null && isPostJson){
            try {
                data = mapper.writeValueAsString(queryParams);
            } catch (JsonProcessingException e) {
                throw new RuntimeException(e);
            }
        }
        //判断body是否为空 并且要post json
        if (isPostJson && !ObjectUtils.isEmpty(requestBody)) {
            try {
                data = mapper.writeValueAsString(requestBody);
            } catch (JsonProcessingException e) {
                throw new RuntimeException(e);
            }
        }
        /**
         * 用requestBody构建非GET请求的的body参数，形如 var1=v1&var2=v2
         */
        Function<Map<String, Object>, String> paramSerialized = m -> {
            UriComponentsBuilder paramsBuiler = UriComponentsBuilder.newInstance();
            m.forEach((k, v)->{paramsBuiler.queryParam(k, v);});
            String d = paramsBuiler.build().toString();
            return d.substring(1);
        };
        if ( requestBody != null && isPostForm && httpMethod != HttpMethod.GET){
            if (requestBody instanceof Map){
                data = paramSerialized.apply( ((Map<String, Object>) requestBody) );
            }else if(!requestBody.getClass().isPrimitive()){
                /**
                 * 非基本类型，即javabean，需转化
                 */
                String mapStr = JSONUtils.toString(requestBody);
                if (mapStr != null && mapStr.startsWith("{")){
                    Map m = JSONUtils.parse(mapStr, Map.class);
                    if (m != null){
                        data = paramSerialized.apply(m);
                    }
                }
            }
        }
        UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromHttpUrl(url);
        /**
         * 用uriVariables构建路径参数
         */
        if (uriVariables != null){
            uriComponentsBuilder.uriVariables(uriVariables);
        }
        /**
         * queryParams 构建GET请求的查询参数
         */
        if (queryParams != null && httpMethod == HttpMethod.GET){
            for (Map.Entry<String, Object> e : queryParams.entrySet()) {
                //构建查询参数
                uriComponentsBuilder.queryParam(e.getKey(), e.getValue());
            }
        }
        requestEntity = new HttpEntity<>(data, headers);
        String finallyUrl = uriComponentsBuilder.build().toString();

        ResponseEntity<T> responseEntity = this.restTemplate.exchange(finallyUrl, httpMethod, requestEntity, resultType);
//        log.info("----responseEntity:{}---", responseEntity);
        return responseEntity.getBody();
    }
}
